feat(transaction-pay): add TokenPay strategy with Across provider + metrics#7806
feat(transaction-pay): add TokenPay strategy with Across provider + metrics#7806pedronfigueiredo wants to merge 2 commits intomainfrom
Conversation
packages/transaction-pay-controller/src/strategy/token-pay/TokenPayStrategy.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/across/across-submit.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/across/across-submit.ts
Show resolved
Hide resolved
6e9ba0c to
047509a
Compare
packages/transaction-pay-controller/src/strategy/across/across-submit.ts
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/across/across-quotes.ts
Outdated
Show resolved
Hide resolved
| import { getRelayQuotes } from './relay-quotes'; | ||
| import { submitRelayQuotes } from './relay-submit'; | ||
|
|
||
| export class RelayProvider implements TokenPayProvider<RelayQuote> { |
There was a problem hiding this comment.
For the sake of modularity and risk, can we refactor Relay in a dedicated PR and leave as is here?
Would let us have a working control in the clients when testing also.
| /** | ||
| * Deposit funds for Across quote. | ||
| */ | ||
| acrossDeposit = 'acrossDeposit', |
There was a problem hiding this comment.
We actually have a pending task to make relayDeposit more granular, so perpsRelayDeposit and predictRelayDeposit, so should do the same for Across also.
| totalFiat?: string; | ||
|
|
||
| /** Total time spent executing the MetaMask Pay flow, in milliseconds. */ | ||
| executionLatencyMs?: number; |
|
|
||
| - `tokenPay.providerOrder` controls priority (default: `[primaryProvider, 'relay', 'across']`). | ||
| - Each provider can be enabled/disabled via `tokenPay.providers.<id>.enabled`. | ||
| - Providers may also implement capability gating in `supports(...)` (e.g., Across rejects same-chain swaps). |
There was a problem hiding this comment.
This sounds like a good mechanism, but can we abstract to PayStrategy in general so we can accommodate fiat in future also and any strategy?
That way, we could isolate this into it's own dedicated PR for risk and easier review?
| export enum TransactionPayStrategy { | ||
| Bridge = 'bridge', | ||
| Relay = 'relay', | ||
| TokenPay = 'tokenPay', |
There was a problem hiding this comment.
I was assuming this would just be an abstract internal class to remove duplication.
Ideally the client could specify multiple preferences in priority order, and we pick the first that is supported or throw?
Thereby combining the new fallback mechanism and getStrategy?
| continue; | ||
| } | ||
|
|
||
| if (provider.id === 'across' && !config.providers.across.enabled) { |
There was a problem hiding this comment.
Is this breaking the abstraction if it knows about the implementations?
| return { transactionHash }; | ||
| } | ||
|
|
||
| async function executeSingleQuote( |
There was a problem hiding this comment.
I understood the core benefit of the TokenPayStrategy was to remove duplication between the Relay and Across strategies.
But if we're just using it for the fallback logic, would it not be simpler to incorporate that into PayStrategy directly (as mentioned in another comment)?
Then we could create some common token strategy utils to add the origin transactions for example given the duplication?
| return Math.ceil(estimatedGas * gasBuffer); | ||
| } catch (error) { | ||
| log('Gas estimate failed, using fallback', { error }); | ||
| return 900000; |
There was a problem hiding this comment.
We have some feature flags for this too, so another benefit of a common util.
| }; | ||
| } | ||
|
|
||
| function buildDelegationAction(delegation: { |
There was a problem hiding this comment.
This is all done in the client via a constructor callback, so we can decouple delegations from this controller.
| } | ||
|
|
||
| const relayer = quote.fees?.relayerTotal?.amountUsd ?? '0'; | ||
| const app = quote.fees?.app?.amountUsd ?? '0'; |
There was a problem hiding this comment.
I'm worried this isn't the total price impact for the user, but just the Across specific fee, does this definitely include the total impact of the bridge provider itself?
Have we confirmed for example, that the quote results in the requested fee minus the this fee only?
There was a problem hiding this comment.
Good point, I adjusted the provider fee to be the impact just like in the case of relay.
1a4c355 to
f5f13b3
Compare
…etrics - Introduce TokenPay strategy with provider adapter interface and registry - Add Across provider (quotes + submit) and Relay adapter wrapper - Implement Across quote normalization (fees, dust, durations, fiat) and actions API payloads for delegated calls - Add feature flags for tokenPay providers and Across API config - Add Across submit flow (approvals + swap tx), intent completion, and confirmation waits - Gate unsupported cases (same-chain, perps deposits) and block type‑4 authorizationList until Across supports it - Add Across quote latency metrics and execution latency recording in metamaskPay metadata - Add/extend unit tests for Across quotes/submit/supports and publish hook metrics
f5f13b3 to
0164046
Compare
0164046 to
4ee01fe
Compare
Explanation
This PR introduces a TokenPay strategy that routes to provider adapters (Relay + Across), adds an Across provider end‑to‑end, and tracks quote/execution latency and costs. It also enforces current Across limitations (same‑chain swaps, perps deposits, and type‑4 authorization lists) with explicit gating and TODOs.
Key changes
References
Checklist
Note
Medium Risk
Adds a new cross-chain quote/execution provider and rewires strategy selection/execution paths with fallback, which can affect transaction submission behavior and metrics recording; changes are covered by extensive new tests but touch critical payment flows.
Overview
Adds a new
Acrosspay strategy (quotes + submission) alongside Relay/Bridge, with feature-flag-controlled ordered strategy selection and automatic fallback when quote retrieval or execution fails.Extends MetaMask Pay telemetry by recording quote latency on Across quotes, execution submit latency via the
onSubmittedcallback, and persisting it toTransactionMeta.metamaskPay.executionLatencyMs; also enriches quote fees withimpact/impactRatio(Relay + Across) and hardens feature-flag reads with safe defaults.Introduces new transaction types
perpsAcrossDeposit/predictAcrossDepositfor Across deposits and refactors submission flows (Relay and new Across) to sharesubmitSourceTransactions, including nonce clearing, required-transaction tracking, and intent completion updates.Written by Cursor Bugbot for commit 4ee01fe. This will update automatically on new commits. Configure here.